{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# C++的引用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1. 引用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.1 引用基本语法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "① 作用：给变量起别名。\n",
    "\n",
    "② 语法：数据类型 &别名 = 原名"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <iostream>\n",
    "using namespace std;\n",
    "\n",
    "int main()\n",
    "{\n",
    "    //引用基本语法\n",
    "    //数据类型 &别名 = 原名\n",
    "\n",
    "    int a = 10;\n",
    "    //创建引用\n",
    "    int& b = a;\n",
    "\n",
    "    b = 100;\n",
    "\n",
    "    cout << \"a= \" << a << endl;\n",
    "    cout << \"b= \" << a << endl;\n",
    "\n",
    "    system(\"pause\");\n",
    "\n",
    "    return 0;\n",
    "\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "运行结果：  \n",
    " - a= 100  \n",
    " - b= 100  \n",
    " - 请按任意键继续. . ."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.2 引用注意事项"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "① 引用必须初始化。\n",
    "\n",
    "② 引用在初始化后，不可以改变。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <iostream>\n",
    "using namespace std;\n",
    "\n",
    "int main()\n",
    "{\n",
    "    //1、引用必须初始化\n",
    "    int a = 10;\n",
    "    int &b = a; // int &b; 是错误的，必须要初始化\n",
    "\n",
    "    //2、引用在初始化后，不可以改变\n",
    "    int c = 20;\n",
    "    b = c;   // 赋值操作，而不是更改引用。把 c = 20 的数据20给了 b 指向的内存的数据，而 a、b 的指向的内存是一样的。\n",
    "             // 这里并不是 b 指向 c 的内存。\n",
    "\n",
    "    cout << \"a = \" << a << endl;  //a内存中数据变了\n",
    "    cout << \"b = \" << b << endl;\n",
    "    cout << \"c = \" << c << endl;\n",
    "\n",
    "    system(\"pause\");\n",
    "\n",
    "    return 0;\n",
    "\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "运行结果：  \n",
    " - a = 20  \n",
    " - b = 20  \n",
    " - c = 20  \n",
    " - 请按任意键继续. . ."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.3 引用做函数参数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "① 函数传参时，可以利用引用的技术让形参修饰实参。\n",
    "\n",
    "② 可以简化指针修改实参。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <iostream>\n",
    "using namespace std;\n",
    "\n",
    "//1、值传递\n",
    "void mySwap01(int a,int b)\n",
    "{\n",
    "    int temp = a;\n",
    "    a = b;\n",
    "    b = temp;\n",
    "}\n",
    "\n",
    "//2、地址传递\n",
    "void mySwap02(int * a, int * b)\n",
    "{\n",
    "    int temp = *a;\n",
    "    *a = *b;\n",
    "    *b = temp;\n",
    "}\n",
    "\n",
    "//2、引用传递\n",
    "//这里面的&a的实参为a(恰巧为a，恰巧一样)的别名，对&a中的a操作修改，就是对实参a修改\n",
    "void mySwap03(int &a, int &b)  \n",
    "{\n",
    "    int temp = a;\n",
    "    a = b;\n",
    "    b = temp;\n",
    "}\n",
    "\n",
    "int main()\n",
    "{\n",
    "    int a = 10;\n",
    "    int b = 20;\n",
    "\n",
    "    mySwap01(a, b);  //值传递，形参不会修饰实参\n",
    "    \n",
    "    cout << \"a = \" << a << endl;\n",
    "    cout << \"b = \" << b << endl;\n",
    "\n",
    "    mySwap02(&a, &b); //地址传递，形参会修饰实参\n",
    "\n",
    "    cout << \"a = \" << a << endl;\n",
    "    cout << \"b = \" << b << endl;\n",
    "\n",
    "    mySwap03(a, b); //引用传递，形参会修饰实参\n",
    "\n",
    "    cout << \"a = \" << a << endl;\n",
    "    cout << \"b = \" << b << endl;\n",
    "\n",
    "    system(\"pause\");\n",
    "\n",
    "    return 0;\n",
    "\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "运行结果：  \n",
    " - a = 10  \n",
    " - b = 20  \n",
    " - a = 20  \n",
    " - b = 10  \n",
    " - a = 10  \n",
    " - b = 20  \n",
    " - 请按任意键继续. . ."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.4 引用做函数返回值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "① 引用是可以作为函数的返回值存在的。\n",
    "\n",
    "② 不要返回局部变量引用。\n",
    "\n",
    "③ 函数调用可以作为左值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <iostream>\n",
    "using namespace std;\n",
    "\n",
    "//引用做函数的返回值\n",
    "//1、不要返回局部变量的引用\n",
    "int& test01()\n",
    "{\n",
    "    int a = 10; //局部变量存放在四区中的栈区\n",
    "    return a;\n",
    "}\n",
    "\n",
    "//2、函数的调用可以作为左值\n",
    "int& test02()\n",
    "{\n",
    "    static int a = 10;  //加上关键字static，变成静态变量，存放在全局区，全局区上的数据在程序结束后释放掉\n",
    "    return a;   //函数的返回值是a的一个引用\n",
    "}\n",
    "\n",
    "int main()\n",
    "{\n",
    "    /*\n",
    "    int& ref = test01();\n",
    "    cout << \"ref = \" << ref << endl; //第一次结果正确，是因为编译器做了保留\n",
    "    cout << \"ref = \" << ref << endl; //第一次结果正确，是因为栈区a的内存已经释放\n",
    "    */\n",
    "\n",
    "    \n",
    "    int& ref = test02();  //由于返回的是a的引用，所以要用引用来接收，这里用ref来接收，ref为原名a的别名\n",
    "    cout << \"ref = \" << ref << endl; \n",
    "    cout << \"ref = \" << ref << endl; \n",
    "    cout << \"ref = \" << ref << endl; \n",
    "\n",
    "    test02() = 1000;   //对a的引用进行操作，相当于原名a赋值赋值为1000\n",
    "    cout << \"ref = \" << ref << endl; //通过原名a的别名ref访问1000\n",
    "    cout << \"ref = \" << ref << endl;\n",
    "\n",
    "    system(\"pause\");\n",
    "\n",
    "    return 0;\n",
    "\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "运行结果：  \n",
    " - ref = 10  \n",
    " - ref = 10  \n",
    " - ref = 10  \n",
    " - ref = 1000  \n",
    " - ref = 1000  \n",
    " - 请按任意键继续. . ."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.5 引用本质"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "① 引用的本质在C++内部实现是一个指针常量。\n",
    "\n",
    "② C++推荐引用计数，因为语法方便，引用本质是指针常量，但是所有的指针操作编译器都帮我们做了。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <iostream>\n",
    "using namespace std;\n",
    "\n",
    "//发现是引用，转换为 int* const ref = &a;\n",
    "void func(int& ref)\n",
    "{\n",
    "    ref = 100; //ref是引用，转换为 * ref = 100;\n",
    "}\n",
    "\n",
    "int main()\n",
    "{\n",
    "    int a = 10;\n",
    "\n",
    "    //自动转换为 int * const ref = &a; 指针常量是指针不可改，引用不可更改别名。\n",
    "    //虽然指针常量指向的地址不可以更改，但是地址中的值可以更改。\n",
    "    int& ref = a;\n",
    "\n",
    "    ref = 20; //内部发现ref是引用，自动帮我们转换为 *ref = 20; 解引用找到相应的数据改为20\n",
    "\n",
    "    cout << \"a：\" << a << endl;\n",
    "    cout << \"ref：\"  << ref << endl;\n",
    "\n",
    "    func(a);\n",
    "\n",
    "    system(\"pause\");\n",
    "\n",
    "    return 0;\n",
    "\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "运行结果：  \n",
    " - a：20  \n",
    " - ref：20  \n",
    " - 请按任意键继续. . ."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.6 常量引用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "① 作用：常量引用主要用来修饰形参，防止误操作。\n",
    "\n",
    "② 在函数形参列表中，可以加const修饰形参，防止形参改变实参。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <iostream>\n",
    "using namespace std;\n",
    "\n",
    "void showValue(const int& val)\n",
    "{\n",
    "    // val = 1000; 报错，不能修改了\n",
    "    cout << \"val = \" << val << endl;\n",
    "}\n",
    "\n",
    "int main()\n",
    "{\n",
    "    //常量引用\n",
    "    //使用场景：用来修饰形参，防止误操作\n",
    "\n",
    "    /*\n",
    "    int a = 10;\n",
    "    int& ref = 10;  //报错，引用必须引一块合法的内存空间\n",
    "    */\n",
    "\n",
    "    //加上const之后，编译器代码修改为 int temp = 10; const in & ref = temp \n",
    "    const int& ref = 10;\n",
    "    //ref = 20;  //加入const之后变为只读，不可以修改\n",
    "\n",
    "    int a = 100;\n",
    "    showValue(a);\n",
    "    cout << \"a = \" << a << endl;\n",
    "\n",
    "    system(\"pause\");\n",
    "    \n",
    "    return 0;\n",
    "\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "运行结果：  \n",
    " - val = 100  \n",
    " - a = 100  \n",
    " - 请按任意键继续. . ."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.6.3",
   "language": "python",
   "name": "python3.6.3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
